/* ----------------------------- Noble Steed Engine----------------------------*
Authors : Daniel Randle, Alex Bourne
Date Created : Mar 14 2013

File:
	nslight.h

Description:
	This file contains the NSLight class which is the base class for all the lights
	in the game
*---------------------------------------------------------------------------*/

#ifndef NSLIGHT_H
#define NSLIGHT_H

/* ---------------------------------Class NSLight-----------------------------*

Description:
	NSLight will provide all the needed virtual functions for other deriving classes to use

*-------------------------------------------------------------------------------*/

// includes
#include <global.h>
#include <nsmath3d.h>
#include <nsobject.h>


class NSShader;
class NSLightShader;
class NSMesh;
class NSCamera;
class NSObjectReference;
class NSSpotLightReference;
class NSPointLightReference;


class NSLight : public NSObject
{
public:

	NSLight(const std::string & name, 
		const std::string & fileName = "", 
		const std::string & mDirectory = "", 
		const std::string tDirectory = "", 
		float diffuse = 0.0f, 
		float ambient = 0.0f,
		float specularPower = 16.0f,
		float specularIntensity = 0.5f,
		const NSVec3Df & _color = NSVec3Df(1.0f,1.0f,1.0f));

	~NSLight();

	void setDiffuse(float diffuse);
	void setAmbient(float ambient);
	void setColor(const NSVec3Df & _color);
	void setLightShader(NSShader * lShader);

	void changeDiffuse(float amount);
	void changeAmbient(float amount);

	void disableShader();
	void enableShader();

	float getDiffuse() const;
	float getAmbient() const;
	NSVec3Df getColor() const;
	NSShader * getLightShader();

	virtual void draw()=0;
	virtual void drawSingle(unsigned int refID=0)=0;
	virtual void drawLight(const NSMatrix4Df & projCamMat, 
		const NSVec3Df & camPos, 
		const NSVec2Df & screenSize,
		NSObjectReference* ref);
	virtual void init();
	virtual void updateUniforms(const NSMatrix4Df & projCamMat, const NSVec3Df & camPos, const NSVec2Df & screenSize,NSObjectReference* ref);


protected:
	virtual void _setUniforms();
	virtual void _loadMeshAndShader()=0;

	NSMesh * boundingMesh;
	float diffuseIntensity;
	float ambientIntensity;
	float specPower;
	float specIntensity;
	NSVec3Df color;
	NSShader * lShader;

};


class NSPointLight : public NSLight
{
public:
	NSPointLight(const std::string & name, 
		const std::string & fileName = "", 
		const std::string & mDirectory = "", 
		const std::string tDirectory = "", 
		float constant = 0.0f, 
		float linear = 0.0f, 
		float exp = 0.0f, 
		float diffuse = 0.0f, 
		float ambient = 0.0f,
		float specularPower = 16.0f,
		float specularIntensity = 0.5f,
		const NSVec3Df & _color = NSVec3Df(1.0f,1.0f,1.0f));

	~NSPointLight();

	void setAttConstant(float constant);
	void setAttLinear(float linear);
	void setAttExp(float exp);

	void changeAttConstant(float amount);
	void changeAttLinear(float amount);
	void changeAttExp(float amount);

	float getAttConstant() const;
	float getAttLinear() const;
	float getAttExp() const;

	virtual void draw();
	virtual void drawSingle(unsigned int refID=0);
	virtual void drawLight(const NSMatrix4Df & projCamMat, const NSVec3Df & camPos, const NSVec2Df & screenSize,NSPointLightReference* ref);
	virtual void updateUniforms(const NSMatrix4Df & projCamMat, const NSVec3Df & camPos, const NSVec2Df & screenSize,NSPointLightReference* ref);
protected:
	virtual void _setUniforms();
	virtual void _loadMeshAndShader();

	float attConstant;
	float attLinear;
	float attExp;

};

class NSSpotLight : public NSPointLight
{
public:
	NSSpotLight(const std::string & name, 
		const std::string & fileName = "", 
		const std::string & mDirectory = "", 
		const std::string tDirectory = "", 
		float _cutoff = 0.0f, 
		float constant = 0.0f, 
		float linear = 0.0f, 
		float exp = 0.0f, 
		float diffuse = 0.0f, 
		float ambient = 0.0f,
		float specularPower = 16.0f,
		float specularIntensity = 0.5f,
		const NSVec3Df & _color = NSVec3Df(1.0f,1.0f,1.0f),
		const NSVec3Df & _defaultDirection = NSVec3Df(0.0f,0.0f,-1.0f) );

	~NSSpotLight();

	void changeCutoff(float amount);

	float getCutoff() const;
	NSVec3Df getDefaultDirection() const;

	void setCutoff(float _cutoff);
	void setDefaultDirection(const NSVec3Df & _defaultDirection);
	
	virtual void draw();
	virtual void drawSingle(unsigned int refID=0);
	virtual void drawLight(const NSMatrix4Df & projCamMat, const NSVec3Df & camPos, const NSVec2Df & screenSize,NSSpotLightReference* ref);
	virtual void updateUniforms(const NSMatrix4Df & projCamMat, const NSVec3Df & camPos, const NSVec2Df & screenSize,NSSpotLightReference* ref);

private:
	virtual void _setUniforms();
	virtual void _loadMeshAndShader();

	float cutoff;
	NSVec3Df defaultDirection;
};

class NSDirectionLight : public NSLight
{
public:
	NSDirectionLight(
		const std::string & name,
		const std::string & fileName = "", 
		const std::string & mDirectory = "",
		const std::string & tDirectory = "", 
		const NSVec3Df & _direction = NSVec3Df(0.0f,0.0f,1.0f), 
		float diffuse = 0.3f, 
		float ambient = 0.1f,
		float specularPower = 16.0f,
		float specularIntensity = 0.5f,
		const NSVec3Df & _color = NSVec3Df(1.0f,1.0f,1.0f) );

	~NSDirectionLight();

	void setDirection(const NSVec3Df & _direction);

	NSVec3Df getDirection() const;

	virtual void draw();
	virtual void drawSingle(unsigned int refID=0);
	virtual void drawLight(const NSMatrix4Df & projCamMat, const NSVec3Df & camPos, NSVec2Df & screenSize, NSObjectReference* ref);
	
	void updateUniforms(const NSMatrix4Df & projCamMat, const NSVec3Df & camPos,NSVec2Df & screenSize,NSObjectReference* ref);

private:
	virtual void _setUniforms();
	virtual void _loadMeshAndShader();

	NSVec3Df direction;

};

#endif